package com.cloudkinto.service.wr.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.BeanConvert;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.dto.order.returns.product.OrProductPageDto;
import com.cloudkinto.dto.product.ProductMinSizeDto;
import com.cloudkinto.entity.*;
import com.cloudkinto.enumType.operate.OperateTypeEnum;
import com.cloudkinto.service.channel.LogisticsChannelService;
import com.cloudkinto.service.company.CompanyService;
import com.cloudkinto.service.cost.CostService;
import com.cloudkinto.service.ft.FreightFarawaySurchargeService;
import com.cloudkinto.service.ft.FreightOverSurchargeService;
import com.cloudkinto.service.ft.FreightTempService;
import com.cloudkinto.service.ob.OperateBillService;
import com.cloudkinto.service.operate.OperateRecordService;
import com.cloudkinto.service.order.returns.OrderReturnService;
import com.cloudkinto.service.regular.vo.OrderPackageRes;
import com.cloudkinto.service.regular.vo.ProductMemoMsg;
import com.cloudkinto.service.sc.ScFarawayInfoRuleService;
import com.cloudkinto.service.sc.ScOverInfoRuleService;
import com.cloudkinto.service.warehouse.WarehouseService;
import com.cloudkinto.service.wr.QuotationSchemeService;
import com.cloudkinto.service.wr.WarehouseRentService;
import com.cloudkinto.service.zone.ZoneTempService;
import com.cloudkinto.utils.BeanCopierUtils;
import com.cloudkinto.vo.channel.lc.LcOptionRes;
import com.cloudkinto.vo.channel.lc.LcRuleDetailRes;
import com.cloudkinto.vo.company.CompanyListVo;
import com.cloudkinto.vo.company.CompanyRes;
import com.cloudkinto.vo.cost.*;
import com.cloudkinto.vo.ft.FreightStatusUpdateReq;
import com.cloudkinto.vo.ft.FreightTempPageVo;
import com.cloudkinto.vo.ft.surcharge.FreightOverScEt;
import com.cloudkinto.vo.lc.LcPageVo;
import com.cloudkinto.vo.ob.ChannelEt;
import com.cloudkinto.vo.ob.OperateBillPageVo;
import com.cloudkinto.vo.ob.QsListEtVo;
import com.cloudkinto.vo.order.returns.pack.OrPackDetailRes;
import com.cloudkinto.vo.sc.ScFarawayInfoPageVo;
import com.cloudkinto.vo.wr.*;
import com.cloudkinto.vo.wr.cost.OrderInputCostReq;
import com.cloudkinto.vo.wr.cost.OrderOutCostReq;
import com.cloudkinto.vo.wr.qs.*;
import com.cloudkinto.vo.wr.trial.*;
import com.cloudkinto.vo.zone.ZoneTempRuleAddReq;
import com.cloudkinto.vo.zone.ZoneTempTestRes;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author hua
 * @since 2024-11-15
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class QuotationSchemeServiceImpl extends ServiceImpl<QuotationSchemeDao, QuotationSchemeDo> implements QuotationSchemeService {
    @Autowired
    private QuotationSchemeDao dao;
    @Autowired
    private QuotationItemDao quotationItemDao;
    @Autowired
    private QuotationCustomerDao qsCustomerDao;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private CompanyService companyService;
    @Autowired
    private LogisticsChannelDao logisticsChannelDao;
    @Autowired
    private LogisticsChannelService logisticsChannelService;
    @Autowired
    private FreightTempService freightTempService;
    @Autowired
    private OperateBillService operateBillService;
    @Autowired
    private WarehouseRentService warehouseRentService;
    @Autowired
    private ZoneTempService zoneTempService;
    @Autowired
    private FreightTempWeightDao freightTempWeightDao;
    @Autowired
    private FreightTempZonePriceDao freightTempZonePriceDao;
    @Autowired
    private OperateRecordService operateRecordService;
    @Autowired
    private FreightFarawaySurchargeService freightFarawaySurchargeService;
    @Autowired
    private FreightOverSurchargeService freightOverSurchargeService;
    @Autowired
    private ProductDao productDao;
    @Autowired
    private ScFarawayInfoRuleService farawayInfoRuleService;
    @Autowired
    private ScOverInfoRuleService scOverInfoRuleService;
    @Autowired
    private ScOverRuleDao scOverRuleDao;
    @Autowired
    private OrderReturnDao orderReturnDao;
    @Autowired
    private OrderReturnService orderReturnService;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private QuotationSchemeDao quotationDao;
    @Autowired
    private OperateBillRuleConditionDao operateBillRuleConditionDao;
    @Autowired
    private OperateBillChannelDao operateBillChannelDao;
    @Autowired
    private OperateBillRuleDao operateBillRuleDao;
    @Autowired
    private OperateBillDao operateBillDao;
    @Autowired
    private CostDao costDao;
    @Autowired
    private CostService costService;
    @Autowired
    private OrderOutboundDao orderOutboundDao;
    @Autowired
    private ProductCategoryDao productCategoryDao;

    private static double getTotalWeight(OrderMsgForCostEt orderMsg, OperateBillDo operateBillDo, OperateBillRuleDo rule) {
        double totalWeight;
        if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(operateBillDo.getWeightUnit())) {
            //公制
            totalWeight = orderMsg.getTotalWeight().getValue().doubleValue();
            if (operateBillDo.getWeightCalculateWay() == 1) {
                //体积重和实重最大值
                totalWeight = Math.max(totalWeight, orderMsg.getTotalVolume().getValue().doubleValue() / operateBillDo.getCoefficient());
            }
        } else {
            //英制
            totalWeight = orderMsg.getTotalWeight().getValueBs().doubleValue();
            if (operateBillDo.getWeightCalculateWay() == 1) {
                //体积重和实重最大值
                totalWeight = Math.max(totalWeight, orderMsg.getTotalVolume().getValueBs().doubleValue() / operateBillDo.getCoefficient());
            }
        }
        if (rule.getUnitCarry() == 1) {
            totalWeight = Math.ceil(totalWeight);
        }
        return totalWeight;
    }

    @Override
    public void updateStatus(FreightStatusUpdateReq req, Long userId, Long tenantId) {
        QuotationSchemeDo et = dao.selectById(req.getId());
        if (et == null) return;
        if (et.getStatus() == req.getStatus()) return;
        et.setStatus(req.getStatus());
        dao.updateById(et);
        String msg = et.getStatus() == 1 ? "审核报价方案" : "废弃报价方案";
        operateRecordService.operateAddRecordAndValue(msg, "", et.getId(), userId, null, OperateTypeEnum.Quotation);
    }

    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }

    public void checkName(QsEt addReq, Long id, Long tenantId) {
        if (StringUtils.isBlank(addReq.getQuotationName()))
            throw new BizException(SysConstant.Add_Name_Empty);
        //名称不能重复
        QuotationSchemeDo et = dao.selectOne(new LambdaQueryWrapper<QuotationSchemeDo>()
                .ne(id != null, QuotationSchemeDo::getId, id)
                .eq(QuotationSchemeDo::getQuotationName, addReq.getQuotationName())
                .eq(QuotationSchemeDo::getTenantId, tenantId));
        if (et != null) throw new BizException(SysConstant.Add_Name_Same);
        if (addReq.getInvalidTime().before(DateUtils.passingDate(new Date(), -1)))
            throw new BizException(SysConstant.Qs_InvalidTime_InCorrect);

    }

    public void checkItemAdd(List<QsItemAddReq> reqList, String currencyCode, int quotationItemType) {
        for (QsItemAddReq qsItemAddReq : reqList) {
            this.checkItem(qsItemAddReq, currencyCode, quotationItemType);
        }
    }

    public void checkItem(QsItemAddReq qsItemAddReq, String currencyCode, int quotationItemType) {
        if (quotationItemType == 0) {
            FreightTempDo et = freightTempService.getById(qsItemAddReq.getThirdId());
            if (et == null) return;
            if (!Objects.equals(et.getCurrencyCode(), currencyCode))
                throw new BizException(SysConstant.Qs_Freight_CurrencyCode_NotSame);
        } else if (quotationItemType == 1) {
            OperateBillDo et = operateBillService.getById(qsItemAddReq.getThirdId());
            if (et == null) return;
            if (!Objects.equals(et.getCurrencyCode(), currencyCode))
                throw new BizException(SysConstant.Qs_OperateBill_CurrencyCode_NotSame);
        } else if (quotationItemType == 2) {
            WarehouseRentDo et = warehouseRentService.getById(qsItemAddReq.getThirdId());
            if (et == null) return;
            if (!Objects.equals(et.getCurrencyCode(), currencyCode))
                throw new BizException(SysConstant.Qs_WhRent_CurrencyCode_NotSame);
        } else {
            throw new BizException(SysConstant.No_Data);
        }
    }

    @Override
    public Object add(QsAddReq req, Long userId, Long tenantId) {
        //todo 判断物流渠道  就算物流渠道不支持该仓库 也可以出现在物流费下拉框，但必须有对应币种的物流费，或者物流渠道支持该仓库
        //判断报价方案名称
        this.checkName(req, null, tenantId);
//        for (QsCustomerEt customer : req.getCustomers()) {
//            QuotationSchemeDo et = dao.getQsByCompanyId(customer.getCompanyId(), req.getStorageId());
//            if (et != null) {
//                throw new BizException(SysConstant.Qs_Customer_Exist_InTime_WithName, customer.getCompanyCode(), et.getQuotationName());
//            }
//        }
        this.checkItemAdd(req.getFreightItems(), req.getCurrencyCode(), 0);
        this.checkItemAdd(req.getOperateBillItems(), req.getCurrencyCode(), 1);
        this.checkItemAdd(req.getRentItems(), req.getCurrencyCode(), 2);
        QuotationSchemeDo entityDo = new QuotationSchemeDo();
        BeanUtils.copyProperties(req, entityDo);
        dao.insert(entityDo);
        this.checkCompany(entityDo, req.getCustomers());
        this.insertCustomer(req.getCustomers(), entityDo.getId());
        this.insetQsItem(req.getFreightItems(), entityDo.getId());
        this.insetQsItem(req.getOperateBillItems(), entityDo.getId());
        this.insetQsItem(req.getRentItems(), entityDo.getId());

        operateRecordService.operateAddRecordAndValue("创建", "", entityDo.getId(), userId, null, OperateTypeEnum.Quotation);

        return entityDo.getId();
    }

    public void insertCustomer(List<QsCustomerEtVo> customers, Long id) {
        //客户
        for (QsCustomerEtVo customer : customers) {
            QuotationCustomerDo qc = new QuotationCustomerDo();
            qc.setQuotationId(id);
            qc.setCompanyId(customer.getCompanyId());
            qsCustomerDao.insert(qc);
        }
    }

    public void insetQsItem(List<QsItemAddReq> qsItems, Long quotationId) {
        if (qsItems == null || qsItems.isEmpty()) return;
        for (QsItemAddReq freightItem : qsItems) {
            QuotationItemDo qsItemDo = new QuotationItemDo();
            BeanUtils.copyProperties(freightItem, qsItemDo);
            qsItemDo.setQuotationId(quotationId);
            quotationItemDao.insert(qsItemDo);
        }
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    public void checkItem(List<QsItemUpdateReq> reqList, String currencyCode, int quotationItemType) {
        for (QsItemUpdateReq qsItemAddReq : reqList) {
            if (!qsItemAddReq.isEdit()) continue;
            this.checkItem(qsItemAddReq, currencyCode, quotationItemType);
        }
    }

    @Override
    public Object update(QsUpdateReq req, Long userId, Long tenantId) {
        //判断报价方案名称
        this.checkName(req, req.getId(), tenantId);
//        for (QsCustomerEt customer : req.getCustomers()) {
//            QuotationSchemeDo et = dao.getQsByCompanyId(customer.getCompanyId(), req.getStorageId());
//            if (et != null && !Objects.equals(et.getId(), req.getId())) {
//                throw new BizException(SysConstant.Qs_Customer_Exist_InTime_WithName, customer.getCompanyCode(), et.getQuotationName());
//            }
//        }

        QuotationSchemeDo entityDo = dao.selectById(req.getId());
        if (!Objects.equals(entityDo.getTenantId(), tenantId)) return null;
        this.checkItem(req.getFreightItems(), entityDo.getCurrencyCode(), 0);
        this.checkItem(req.getOperateBillItems(), entityDo.getCurrencyCode(), 1);
        this.checkItem(req.getRentItems(), entityDo.getCurrencyCode(), 2);
        this.checkCompany(entityDo, req.getCustomers());
        BeanUtils.copyProperties(req, entityDo);
        dao.updateById(entityDo);

        List<QuotationItemDo> oldItems = quotationItemDao.selectList(new LambdaQueryWrapper<QuotationItemDo>()
                .eq(QuotationItemDo::getQuotationId, entityDo.getId()));
        List<Long> newIds = new ArrayList<>();
        this.getNewIds(newIds, req.getFreightItems());
        this.getNewIds(newIds, req.getOperateBillItems());
        this.getNewIds(newIds, req.getRentItems());
        List<Long> deleteIds = oldItems.stream().map(QuotationItemDo::getId).filter(i -> !newIds.contains(i)).collect(Collectors.toList());
        if (!deleteIds.isEmpty()) quotationItemDao.updateDelete(deleteIds, userId);
        //判断操作费 调整如果减少 减少后金额必须大于0
        this.updateQsItem(req.getFreightItems(), entityDo.getId());
        this.updateQsItem(req.getOperateBillItems(), entityDo.getId());
        this.updateQsItem(req.getRentItems(), entityDo.getId());
        qsCustomerDao.updateDelete(entityDo.getId());
        this.insertCustomer(req.getCustomers(), entityDo.getId());

        operateRecordService.operateAddRecordAndValue("编辑", "", entityDo.getId(), userId, null, OperateTypeEnum.Quotation);
        return entityDo.getId();
    }

    public void checkCompany(QuotationSchemeDo entityDo, List<QsCustomerEtVo> customers) {
        //客户 判断客户 期间内是不是就这一个报价
        Map<String, Object> map = new HashMap<>();
        map.put("tenantId", entityDo.getTenantId());
        map.put("quotationId", entityDo.getId());
        map.put("quotationType", entityDo.getQuotationType());
        map.put("storageId", entityDo.getStorageId());
        map.put("invalidTime", DateUtils.dateFormatToString(entityDo.getInvalidTime()));
        map.put("effectiveTime", DateUtils.dateFormatToString(entityDo.getEffectiveTime()));
        //获取时间区间内 没有报价的客户，排除已失效的报价 和废弃的报价
        List<CompanyListVo> companyListForQs = companyDao.getCompanyListForQs(map);
        Map<Long, String> companyMap = companyListForQs.stream().collect(Collectors.toMap(CompanyListVo::getCompanyId, CompanyListVo::getCompanyCode));
        for (QsCustomerEtVo customer : customers) {
            if (companyMap.get(customer.getCompanyId()) == null) {
                throw new BizException(SysConstant.Qs_InvalidTime_Company_Exist, customer.getCompanyCode());
            }
        }
    }

    public void updateQsItem(List<QsItemUpdateReq> qsUpdateItems, Long quotationId) {
        //todo 判断物流渠道  就算物流渠道没有选择该仓库 也可以出现在物流费下拉框，但必须有对应币种的物流费，或者选择了该仓库
        if (qsUpdateItems == null || qsUpdateItems.isEmpty()) return;
        for (QsItemUpdateReq qsItemUpdateReq : qsUpdateItems) {
            if (qsItemUpdateReq.getId() != null && !qsItemUpdateReq.isEdit()) continue;
            QuotationItemDo qsItemDo = new QuotationItemDo();
            BeanUtils.copyProperties(qsItemUpdateReq, qsItemDo);
            if (qsItemUpdateReq.getId() == null) {
                //插入

                qsItemDo.setQuotationId(quotationId);
                quotationItemDao.insert(qsItemDo);
            } else {
                quotationItemDao.updateById(qsItemDo);
            }
        }

    }

    public void getNewIds(List<Long> newIds, List<QsItemUpdateReq> qsUpdateItems) {
        if (qsUpdateItems == null || qsUpdateItems.isEmpty()) return;
        newIds.addAll(qsUpdateItems.stream().map(QsItemUpdateReq::getId).filter(Objects::nonNull).collect(Collectors.toList()));
    }

    @Override
    public int delete(Long id, Long userId, Long tenantId) {
        //已审核状态不可以删除
        return dao.updateDelete(id, userId, tenantId);
    }

    @Override
    public QsDetailRes detail(Long id, Long tenantId) {
        QuotationSchemeDo entityDo = dao.selectById(id);
        QsDetailRes res = new QsDetailRes();
        BeanUtils.copyProperties(entityDo, res);
        List<QsItemDetailVoVo> list = quotationItemDao.list(id, null, tenantId, null);
        //按照类型分类
        Map<Integer, List<QsItemDetailVoVo>> qsItemTypeMap = list.stream().collect(Collectors.groupingBy(QsItemDetailVoVo::getQuotationItemType));
        if (qsItemTypeMap.get(0) != null)
            res.setFreightItems(BeanCopierUtils.listCopyMapper(qsItemTypeMap.get(0), QsItemDetailVoVo.class, QsFreightResVo.class));
        if (qsItemTypeMap.get(1) != null) {
            res.setOperateBillItems(BeanCopierUtils.listCopyMapper(qsItemTypeMap.get(1), QsItemDetailVoVo.class, QsOperateBillResVo.class));
        }
        if (qsItemTypeMap.get(2) != null)
            res.setRentItems(BeanCopierUtils.listCopyMapper(qsItemTypeMap.get(2), QsItemDetailVoVo.class, QsWhRentDetailRes.class));
        List<QsCustomerVoVo> customerDoList = qsCustomerDao.getCustomerForQs(Collections.singletonList(entityDo.getId()));
        List<QsCustomerEtVo> qsCustomerEtVos = BeanCopierUtils.listCopyMapper(customerDoList, QsCustomerVoVo.class, QsCustomerEtVo.class);
        res.setCustomers(qsCustomerEtVos);
        res.setOperateResList(operateRecordService.getOperateList(id, OperateTypeEnum.Quotation));

        return res;
    }

    @Override
    public SingleResult pageInit() {
        return SingleResult.success("");
    }

    @Override
    public List<QsPageVo> getList(Map<String, Object> map) {
        List<QsPageVo> list = dao.list(map);
        return list;
    }

    @Override
    public PageResult getListPage(Map<String, Object> map) {
        IPage<QsPageVo> page = pageInit(map);
        page = dao.list(page, map);
        Map<Long, List<QsCustomerEtVo>> customers = this.getCustomers(page.getRecords().stream().map(QsPageVo::getId).collect(Collectors.toList()));
        for (QsPageVo record : page.getRecords()) {
            record.setCustomers(customers.get(record.getId()));
        }
        PageResult result = new PageResult(page.getRecords(), (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    public Map<Long, List<QsCustomerEtVo>> getCustomers(List<Long> ids) {
        Map<Long, List<QsCustomerEtVo>> result = new HashMap<>();
        if (ids == null || ids.isEmpty()) return result;

        List<QsCustomerVoVo> customerDoList = qsCustomerDao.getCustomerForQs(ids);
        Map<Long, List<QsCustomerVoVo>> collect = customerDoList.stream().collect(Collectors.groupingBy(QsCustomerVoVo::getQuotationId));
        for (Long quotationId : collect.keySet()) {
            result.put(quotationId, BeanConvert.INSTANCE.qsCustomerEt(collect.get(quotationId)));
        }
        return result;
    }

    private IPage<QsPageVo> pageInit(Map<String, Object> map) {
        IPage<QsPageVo> page = new Page<>();
        page.setSize(map.get("pageSize") != null ? Long.parseLong(map.get("pageSize").toString()) : 10);
        page.setCurrent(map.get("current") != null ? Long.parseLong(map.get("current").toString()) : 1);
        return page;
    }

    @Override
    public List<CompanyListVo> listCustomerByWhCode(Map<String, Object> map, Long userId, String source) {
        if (map.get("invalidTime") == null) return new ArrayList<>();
        //如果结束时间是在今天之前
        Date date = DateUtils.stringFormatToDate(map.get("invalidTime").toString());
        if (date.before(DateUtils.passingDate(new Date(), -1))) {
            List<CompanyRes> companys = companyService.getCompanyList(userId, Long.parseLong(map.get("tenantId").toString()), source);
            return BeanCopierUtils.listCopyMapper(companys, CompanyRes.class, CompanyListVo.class);
        }
        return companyDao.getCompanyListForQs(map);
    }

    /**
     * 获取物流渠道下拉框
     * 就算物流渠道不支持该仓库 也可以出现在物流费下拉框，但必须有对应币种的物流费，或者物流渠道支持该仓库 未实现
     * 目前只要绑定了仓库 就能出现在下拉框
     */
    @Override
    public List<ChannelEt> channelList(Map<String, Object> map) {
        map.put("bindWarehouseQuantity", 1);
        map.put("enable", 0);
        List<LcPageVo> list = logisticsChannelDao.list(map);
        List<ChannelEt> result = BeanCopierUtils.listCopyMapper(list, LcPageVo.class, ChannelEt.class);
        return result;
    }

    /**
     * 获取物流费下拉框
     */
    @Override
    public List<FreightTempPageVo> freightList(Map<String, Object> map) {
        //获取类型物流费 启用状态的物流费
        map.put("type", "freight");
        map.put("status", 0);
        return freightTempService.getList(map);
    }

    /**
     * 获取操作费列表
     */
    @Override
    public List<QsListEtVo> operateBillItemList(Map<String, Object> map) {
        if (map.get("currencyCode") == null || StringUtils.isBlank(map.get("currencyCode").toString()))
            return new ArrayList<>();
        List<OperateBillPageVo> list = operateBillService.getList(map);
        List<QsListEtVo> resList = new ArrayList<>();
        for (OperateBillPageVo obEt : list) {
            QsListEtVo et = new QsListEtVo(obEt.getId(), obEt.getBillItemName(), obEt.getType(), obEt.getBillType(), obEt.getCurrencyCode(), obEt.getTips());
            et.setAdjustmentStatus(0);
            resList.add(et);
        }
        return resList;
    }

    /**
     * 获取仓租费列表
     */
    @Override
    public List<WhRentPageVo> warehouseRentList(Map<String, Object> map) {
        if (map.get("currencyCode") == null || StringUtils.isBlank(map.get("currencyCode").toString())) {
            return new ArrayList<>();
        } else {
            map.put("currencyCode", Collections.singletonList(map.get("currencyCode").toString()));
        }
        return warehouseRentService.getList(map);
    }

    /**
     * 根据费用id 获取关联的报价方案id
     */
    @Override
    public List<QsPageVo> relatedQsList(Map<String, Object> map) {
        List<QsPageVo> qsPageVos = dao.relatedQsList(map);
        Map<Long, List<QsCustomerEtVo>> customers = this.getCustomers(qsPageVos.stream().map(QsPageVo::getId).collect(Collectors.toList()));
        for (QsPageVo record : qsPageVos) {
            record.setCustomers(customers.get(record.getId()));
        }
        return qsPageVos;
    }

    /**
     * 运费试算 根据报价方案 获取报价方案的物流渠道
     */

    @Override
    public List<LcCodeRes> getLcForTrial(Long qsId, Long tenantId) {
        List<QsItemDetailVoVo> list = quotationItemDao.list(qsId, null, tenantId, 0);
        List<LcCodeRes> lcList = new ArrayList<>();
        Set<Long> set = new HashSet<>();
        for (QsItemDetailVoVo qsItemDetailVo : list) {
            if (set.contains(qsItemDetailVo.getChannelId())) continue;
            set.add(qsItemDetailVo.getChannelId());
            lcList.add(new LcCodeRes(qsItemDetailVo.getChannelId(), qsItemDetailVo.getChannelCode(), qsItemDetailVo.getChannelName()));
        }
        return lcList;
    }

    @Override
    public List<TrialFreightRes> omsTrialFreightFee(TrialOmsReq req) {
        if (req == null) {
            return new ArrayList<>();
        }
        CompanyDo companyDo = companyDao.selectById(req.getCompanyId());
        if (companyDo == null) return new ArrayList<>();
        // 获取报价方案
        TrialFreightUtilReq manualReq = new TrialFreightUtilReq();
        BeanUtils.copyProperties(req, manualReq);
        manualReq.setOrderLimit(1);
        // 获取报价方案
        List<TrialFreightRes> resList = this.trialFreightFee(manualReq, companyDo.getTenantId());
        return resList;
    }

    @Override
    public List<TrialFreightRes> ompTrialFreightFee(TrialOmpReq req, Long tenantId) {
        TrialFreightUtilReq manualReq = new TrialFreightUtilReq();
        BeanUtils.copyProperties(req, manualReq);
        // 获取报价方案
        List<TrialFreightRes> resList = this.trialFreightFee(manualReq, tenantId);
        return resList;
    }

    /**
     * omp运费试算 - 根据报价方案获取 物流渠道-物流费，
     * oms运费试算 根据公司仓库获取支持的物流渠道，根据物流渠道 获取在有效期内，且支持该客户的报价方案。
     */
    public List<TrialFreightRes> trialFreightFee(TrialFreightUtilReq req, Long tenantId) {
        List<TrialFreightRes> resList = new ArrayList<>();
        //如果物流费 体积重选择了 三边和 则 体积重 = 长 + 宽 + 高； 计费重 = 结束值
        //获取报价方案 物流费的 的分区
        if (req.getGoodsType() == 2) {
            if (req.getProducts() == null || req.getProducts().isEmpty()) {
                resList.add(new TrialFreightRes(null, null, null, "参数错误", "参数错误", "参数错误"));
                return resList;
            }
        } else if (req.getGoodsType() == 3) {
            if (req.getBoxes() == null || req.getBoxes().isEmpty()) {
                resList.add(new TrialFreightRes(null, null, null, "参数错误", "参数错误", "参数错误"));
                return resList;
            }
        }
        if (req.getCompanyId() != null) {
            //根据公司获取 报价id
            Long qsId = this.getQsId(req.getCompanyId(), req.getWarehouseId());
            req.setQsId(qsId);
        }
        //获取物流费列表 quotationItemType = 0
        List<QsItemDetailVoVo> list = quotationItemDao.list(req.getQsId(), req.getWarehouseId(), tenantId, 0);
        Map<Long, QsItemDetailVoVo> qsItemMap = list.stream().collect(Collectors.toMap(QsItemDetailVoVo::getChannelId, i -> i));
        List<Long> choiceChannelId = req.getLc() != null ? req.getLc().stream().map(LcCodeRes::getChannelId).filter(i -> i > 0).collect(Collectors.toList()) : null;
        Set<Long> companyChannelIds = new HashSet<>();
        Map<Long, LcOptionRes> channelCollect = new HashMap<>();
        if (req.getCompanyId() != null) {//说明是oms过来 获取公司支持的物流渠道
            //oms 新建 只需要获取 选择的物流渠道的运费方式，不需要计算这个报价下所有的物流方式 增加速度
            List<Long> collect;
            if (req.getLc() != null && !req.getLc().isEmpty()) {
                //出库单新建过来 手动选择的物流方式
                collect = req.getLc().stream().map(LcCodeRes::getChannelId).collect(Collectors.toList());
            } else {
                //oms的运费试算
                collect = new ArrayList<>();
            }
            List<LcOptionRes> lcList = logisticsChannelService.getLcForOut(req.getWarehouseId(), req.getCompanyId(), tenantId);
            channelCollect = lcList.stream().filter(i -> collect.isEmpty() || collect.contains(i.getId()) || req.getAutoChooseCheap() == 1).collect(Collectors.toMap(LcOptionRes::getId, i -> i));
            companyChannelIds = channelCollect.keySet();

        } else {
            //说明是运费试算过来的， 获取新建时 选择了 自动选择最便宜的物流方式 这边就获取这个报价下所有物流渠道的运费
            companyChannelIds = qsItemMap.keySet();
        }
        Map<Long, String> carrierMap = new HashMap<>();
        if (!companyChannelIds.isEmpty()) {
            carrierMap = logisticsChannelService.list(new LambdaQueryWrapper<LogisticsChannelDo>().in(LogisticsChannelDo::getId, companyChannelIds)).stream().collect(Collectors.toMap(LogisticsChannelDo::getId, LogisticsChannelDo::getCarrier));
        }
        //旧版规则
        int totalCount = 0;
        boolean zhaiFlag = false;
        OrderPackageRes packageRes = null;
        if (req.getGoodsType() == 2) {
            Set<String> clothesSet = new HashSet<>();
            for (TrialProductReq product : req.getProducts()) {
                totalCount += product.getQuantity();
                if (clothesSet.size() == 2) {
                    continue;
                }
                if (clothesSet.size() < 2) {
                    if (product.getCategoryId() == null) {
                        continue;
                    }
                    ProductCategoryDo categoryDo = productCategoryDao.selectById(product.getCategoryId());
                    if (categoryDo == null) {
                        continue;
                    }
                    if (categoryDo.getFullPathName().contains("雑貨タオル")) {
                        clothesSet.add("雑貨タオル");
                    } else if (categoryDo.getFullPathName().contains("衣類")) {
                        clothesSet.add("衣類");
                    }
                }
            }
            boolean clothes = clothesSet.size() == 2;
            //包裹信息
            packageRes = this.getPackageList(req.getProducts());
            zhaiFlag = packageRes.isZhaiFlag();
            List<Long> productIds = req.getProducts().stream().map(TrialProductReq::getProductId).distinct().collect(Collectors.toList());
            List<List<ProductMemoMsg>> packageList = packageRes.getPackageList();
            if (packageList.size() > 2 || clothes || totalCount > 2 ||
                    (StaticDict.Store_PlatformCode.Qoo10.getValue().equals(req.getPlatformCode()) && productIds.size() == 1 && totalCount == 2 && packageList.size() == 2)) {
                //如果 超过 1.5 的产品超过两个 那么也是宅急便 1.6 1.6 1.6
                zhaiFlag = true;
            }
        }
        for (Long channelId : companyChannelIds) {
            QsItemDetailVoVo item = qsItemMap.get(channelId);
            if (item == null) {
                resList.add(new TrialFreightRes(channelId, channelCollect.get(channelId).getChannelCode(), channelCollect.get(channelId).getChannelName(), "未匹配方案报价", "未匹配方案报价", "未匹配方案报价"));
                continue;
            }
            if (choiceChannelId != null && !choiceChannelId.isEmpty() && !choiceChannelId.contains(-1L) && !choiceChannelId.contains(item.getChannelId()))
                continue;
            if (item.getStatus() == 2) {
                resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "方案已废弃", "方案已废弃", "方案已废弃"));
                continue;
            }
//            if (item.getStatus() == 0) {
//                resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "方案未审核"));
//                continue;
//            }
            FreightTempDo freightTempDo = freightTempService.getById(item.getThirdId());
            if (freightTempDo == null) {
                resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "物流费消失了", "物流费消失了", "物流费消失了"));
                continue;
            }

            SizeArrRes sizeArr = this.getSizeArr(freightTempDo, req);
            //计算尺寸 长 宽 高 重 计费重 体积重 体积
            Double[] sizeCm = sizeArr.getSizeCm();
            Double[] sizeIn = sizeArr.getSizeIn();
            double declarePrice = sizeArr.getDeclarePrice();

            if (req.getCompanyId() != null) { //判断下单规则
                //目前关系都是  介于默认包含两边
                LcOptionRes lcRes = channelCollect.get(channelId);
                boolean flag = true;
                String ruleDetail = "";
                for (LcRuleDetailRes lcRule : lcRes.getRules()) {
                    //判断下单规则 todo 要不要也改成 左开右闭
                    flag = this.jugByCalType(lcRule.getCalculateType(), lcRule.getOperateSign(), lcRule.getStartValue().doubleValue(),
                            lcRule.getEndValue().doubleValue(),
                            StaticDict.OMP_UnitMeasurement.In.getValue().equals(lcRes.getSizeUnit()) ? sizeIn : sizeCm);
                    if (!flag) {
                        ruleDetail = lcRule.getRuleDetail();
                        break;
                    }
                }
                if (!flag) {
                    //说明物流渠道下单条件不满足
                    resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "物流渠道下单限制", "当前物流渠道限制", "当前物流渠道限制:" + ruleDetail));
                    continue;
                }
            }

            if (req.getGoodsType() == 2) {
                if (packageRes == null) {
                    resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "分包错误", "分包错误", "分包错误"));
                    continue;
                }

                if (channelId == 3) {
//                    if (!zhaiFlag) {
//                        resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "物流渠道下单限制", "当前物流渠道限制", "当前物流渠道限制:包裹数量大于2 或者 同时包含 雑貨タオル 和 衣類 两种产品类型 才可分配黑猫宅急便"));
//                        continue;
//                    }
                } else if (channelId == 2) {
                    //投涵多件
                    if (zhaiFlag || packageRes.getPackageList().size() != 2) {
                        resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "物流渠道下单限制", "当前物流渠道限制", "当前物流渠道限制:包裹数量等于2且最短边小于3 才可分配投涵多件"));
                        continue;
                    }
                }
                else if (channelId == 1) {
                    //黑猫投涵
                    if (zhaiFlag || packageRes.getPackageList().size() != 1) {
                        resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "物流渠道下单限制", "当前物流渠道限制", "当前物流渠道限制:包裹数量等于1且最短边小于3 才可分配ネコポス"));
                        continue;
                    }
                }
            }

            //获取物流费分区
            ZoneTempTestRes zoneTempTestRes = zoneTempService.testZone(item.getThirdId(), req.getCountryCode(), req.getPostcode(), "freight");
            if (zoneTempTestRes.getZone() == null) {
                resList.add(new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), "未匹配到分区", "分区校验", "分区校验:未匹配到分区"));
                continue;
            }
            List<String> zones = zoneTempTestRes.getZoneList().stream().map(ZoneTempRuleAddReq::getZone).distinct().collect(Collectors.toList());
            //重量段 有了分区之后 根据分区 匹配最便宜的重量段价格， 如果重量段价格未匹配 则是0
            List<FreightTempWeightDo> weightDoList = freightTempWeightDao.selectList(new LambdaQueryWrapper<FreightTempWeightDo>().eq(FreightTempWeightDo::getTempId, freightTempDo.getId())
                    .eq(FreightTempWeightDo::getWeightType, "freight"));
            Map<String, List<SurchargeFeeRes>> zoneSurMap = new HashMap<>();
            if (freightTempDo.getVolumeWeightCalculateWay() == 1) {
                this.getLogBaseFeeForTrilateralSum(zoneSurMap, weightDoList, zones, item, StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(freightTempDo.getSizeUnit()) ? sizeCm : sizeIn);
            } else {
                this.getLogBaseFeeNoVolume(zoneSurMap, weightDoList, zones, item, StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(freightTempDo.getSizeUnit()) ? sizeCm : sizeIn);
            }
            //获取附加费
            //偏远地区
            Map<Integer, FreightFarawaySurchargeDo> farawayC = freightFarawaySurchargeService.getFarawaySc(freightTempDo.getType(), freightTempDo.getId()).stream().collect(Collectors.toMap(FreightFarawaySurchargeDo::getFarawayRuleType, i -> i));
            //超长超重附加费
            List<FreightOverScEt> overScList = freightOverSurchargeService.getOverScList(freightTempDo.getType(), freightTempDo.getId());
            Map<Integer, FreightOverScEt> overC = overScList.stream().collect(Collectors.toMap(FreightOverScEt::getSurchargeType, i -> i));
            //根据超长附加费id 和 分区id 获取分区价格
            Map<Long, List<FreightTempZonePriceDo>> overZonePriceMap = new HashMap<>();
            if (!overScList.isEmpty()) {
                List<FreightTempZonePriceDo> surZonPriceDo = freightTempZonePriceDao.selectList(new LambdaQueryWrapper<FreightTempZonePriceDo>()
                        .eq(FreightTempZonePriceDo::getPriceType, "surcharge").in(FreightTempZonePriceDo::getFreightTempWeightId, overScList.stream().map(FreightOverScEt::getId).collect(Collectors.toList()))
                        .in(FreightTempZonePriceDo::getZone, zones));
                overZonePriceMap = surZonPriceDo.stream().collect(Collectors.groupingBy(FreightTempZonePriceDo::getFreightTempWeightId));
            }
            //偏远附加费
            for (StaticDict.Surcharge_Faraway_type valueT : StaticDict.Surcharge_Faraway_type.values()) {
                FreightFarawaySurchargeDo sur = farawayC.get(valueT.getValue());
                if (sur == null) continue;
                double fee = 0d;
                if (StaticDict.Surcharge_Faraway_type.Insurance.getValue().equals(sur.getFarawayRuleType())) {
                    //判断订单有没有保险
                    if (!req.isInsureFlag()) continue;
                    //获取产品的申报价格， 这边默认不转换币种 产品的申报价格 是usd
                    if (req.getInsureMoney() == null) req.setInsureMoney(declarePrice);
                    fee = req.getInsureMoney() * sur.getCommonAddrFee() / 100;
                } else if (StaticDict.Surcharge_Faraway_type.ResidenceSeason.getValue().equals(sur.getFarawayRuleType())) {
                    //住宅地址附加费
                    if (req.getAddrType() != 0) continue;
                    fee = sur.getCommonAddrFee();
                } else if ("signature".equals(valueT.getType())) {
                    //签名附加费
                    if (req.getSignatureType() == null) continue;
                    if (sur.getFarawayRuleType() == null) continue;//没有签名服务
                    if (!Objects.equals(req.getSignatureType(), sur.getFarawayRuleType())) continue;
                    if (!Objects.equals(sur.getFarawayRuleType(), valueT.getValue())) continue;
                    fee = sur.getCommonAddrFee();
                } else {
                    Map<String, Object> farMap = new HashMap<>();
                    farMap.put("farawayRuleId", sur.getFarawayRuleId());

                    List<ScFarawayInfoPageVo> farRuleInfoList = farawayInfoRuleService.getList(farMap);
                    boolean farFlag = false;
                    for (ScFarawayInfoPageVo farD : farRuleInfoList) {
                        //todo 这里要不要判断 省/州 城市
                        farFlag = zoneTempService.jugPostCode(req.getPostcode(), farD.getStartPostcode(), farD.getEndPostcode());
                        if (farFlag) break;
                    }
                    if (!farFlag) continue;
                    //偏远明细规则符合吗
                    fee = sur.getDistinctAddrType() == 0 ? sur.getCommonAddrFee() : req.getAddrType() == 0 ? sur.getResidenceAddrFee() : sur.getBusinessAddrFee();
                }
                for (String zone : zones) {
                    SurchargeFeeRes surchargeFeeRes = new SurchargeFeeRes(valueT.getText(), fee);
                    zoneSurMap.computeIfAbsent(zone, k -> new ArrayList<>()).add(surchargeFeeRes);
                }
            }
            //超长附加费
            for (StaticDict.Surcharge_type valueT : StaticDict.Surcharge_type.values()) {
                FreightOverScEt sur = overC.get(valueT.getValue());
                //分区可能多个 选择最便宜的分区
                if (sur == null) continue;
                if (overZonePriceMap.get(sur.getId()) == null || overZonePriceMap.get(sur.getId()).isEmpty()) continue;
                ScOverRuleDo overEt = scOverRuleDao.selectById(sur.getOverId());
                //获取子表 List
                Map<Long, List<ScOverInfoRuleDo>> scOverC = scOverInfoRuleService.list(new LambdaQueryWrapper<ScOverInfoRuleDo>()
                        .eq(ScOverInfoRuleDo::getOverId, sur.getOverId())).stream().collect(Collectors.groupingBy(ScOverInfoRuleDo::getParentId));
                if (scOverC.get(-1L) == null) continue;
                boolean parentFlag = true;
                for (ScOverInfoRuleDo parent : scOverC.get(-1L)) {
                    List<ScOverInfoRuleDo> oneList = new ArrayList<>();
                    oneList.add(parent);
                    if (scOverC.get(parent.getId()) != null) oneList.addAll(scOverC.get(parent.getId()));
                    boolean flag = true;
                    for (ScOverInfoRuleDo overD : oneList) {
                        if (StaticDict.Sc_Calculate_Type.Country.getValue().equals(overD.getCalculateType())) {//国家
                            List<String> ruleCountry = Arrays.asList(overD.getCountryRegionCodes().split(","));
                            flag = ruleCountry.contains(req.getCountryCode());
                        } else {
                            flag = this.jugByCalType(overD.getCalculateType(), overD.getOperateSign(), overD.getStartValue().doubleValue(), overD.getEndValueDouble(),
                                    StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(overEt.getSizeUnit()) ? sizeCm : sizeIn);
                        }
                        if (parent.getRuleRelation() == 0) {//并且关系
                            if (!flag) break;
                        } else if (parent.getRuleRelation() == 1) {
                            if (flag) break;
                        }
                    }
                    parentFlag = flag;
                    if (overEt.getRuleRelation() == 0) {//并且关系
                        if (!parentFlag) break;
                    } else if (overEt.getRuleRelation() == 1) {
                        if (parentFlag) break;
                    }

                }
                if (!parentFlag) {
                    continue;
                }
                List<FreightTempZonePriceDo> zonePriceDos = overZonePriceMap.get(sur.getId()).stream().filter(i -> i.getAddrType() == null || Objects.equals(i.getAddrType(), req.getAddrType())).sorted(new Comparator<FreightTempZonePriceDo>() {
                    @Override
                    public int compare(FreightTempZonePriceDo o1, FreightTempZonePriceDo o2) {
                        return o1.getZonePrice().compareTo(o2.getZonePrice());
                    }
                }).collect(Collectors.toList());
                for (FreightTempZonePriceDo zonePriceDo : zonePriceDos) {
                    SurchargeFeeRes surchargeFeeRes = new SurchargeFeeRes(valueT.getText(), zonePriceDo.getZonePrice());
                    zoneSurMap.computeIfAbsent(zonePriceDo.getZone(), k -> new ArrayList<>()).add(surchargeFeeRes);
                }
            }
            // 这边单位要换成 和 尺寸单位一致的再返回
            TrialFreightRes res = new TrialFreightRes(item.getChannelId(), item.getChannelCode(), item.getChannelName(), carrierMap.get(item.getChannelId()), freightTempDo.getCurrencyCode(),
                    StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(req.getSizeUnit()) ? sizeCm[4] : sizeIn[4],
                    StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(req.getSizeUnit()) ? sizeCm[5] == null ? "-" : sizeCm[5] + "" : sizeIn[5] == null ? "-" : sizeIn[5] + "", req.getSizeUnit());
            //众多分区中 获取最便宜
            Double cheap = null;
            String cheapZone = null;
            for (String zone : zoneSurMap.keySet()) {
                double fee = zoneSurMap.get(zone).stream().mapToDouble(SurchargeFeeRes::getFee).sum();
                if (cheap == null || cheap > fee) {
                    cheapZone = zone;
                    cheap = fee;
                }
            }
            if (cheap == null) cheap = 0d;
            for (SurchargeFeeRes surchargeFeeRes : zoneSurMap.get(cheapZone)) {
                if ("基础运费".equals(surchargeFeeRes.getItemName())) {
                    res.setLogBaseFee(surchargeFeeRes.getFee());
                    if (!surchargeFeeRes.isMatch()) {
                        res.setPlaceOrderFlag(false);
                        res.setPlaceOrderMsg("称重校验");
                        res.setPlaceOrderDetailMsg("包裹重量超出物流渠道的重量段范围");
                    }
                    break;
                }
            }
            //计算附加费
            res.setSurchargeFee(Math.max(0d, cheap - res.getLogBaseFee()));
            res.setSurchargeList(zoneSurMap.get(cheapZone));
            res.setWhId(req.getWarehouseId());
            resList.add(res);
        }
        resList.sort(new Comparator<TrialFreightRes>() {
            @Override
            public int compare(TrialFreightRes o1, TrialFreightRes o2) {
                if (o1.isPlaceOrderFlag() && !o2.isPlaceOrderFlag()) {
                    return -1;
                } else if (!o1.isPlaceOrderFlag() && o2.isPlaceOrderFlag()) {
                    return 1;
                } else {
                    if (o1.isSuccessFlag() && !o2.isSuccessFlag()) {
                        return -1;
                    } else if (!o1.isSuccessFlag() && o2.isSuccessFlag()) {
                        return 1;
                    } else {
                        int compare = Double.compare(o1.getLogBaseFee() + o1.getSurchargeFee(), o2.getLogBaseFee() + o2.getSurchargeFee());
                        if (compare == 0) {
                            if (Objects.equals(o1.getChannelCode(), o2.getChannelCode())) {
                                return 0;
                            }
                            else if (Objects.equals(o1.getChannelCode(), "yamato_zhai")) {
                                return 1;
                            }
                            else {
                                return Long.compare(o1.getChannelId(), o2.getChannelId());
                            }
                        }
                        else {
                            return compare;
                        }
                    }
                }
            }
        });


        return resList;
    }



    public OrderPackageRes getPackageList(List<TrialProductReq> itemList) {

        if (itemList.stream().mapToInt(TrialProductReq::getQuantity).sum() > 100) {
            return new OrderPackageRes(new ArrayList<>(), true);
        }
        //分包逻辑
        List<List<ProductMemoMsg>> packageList = new ArrayList<>();
        boolean zhaiFlag = false;
        List<Long> productIds = itemList.stream().map(TrialProductReq::getProductId).collect(Collectors.toList());
        Map<Long, ProductMinSizeDto> sizeMap = new HashMap<>();
        if (!productIds.isEmpty()) {
            sizeMap = productDao.getProductMinSize(productIds).stream().collect(Collectors.toMap(ProductMinSizeDto::getProductId, i->i));
        }
        List<ProductMemoMsg> less30List = new ArrayList<>();
        for (TrialProductReq item : itemList) {
            ProductMinSizeDto sizeB = sizeMap.get(item.getProductId());
            if (sizeB == null) {
                continue;
            }
            if (sizeB.getMinSize().compareTo(new BigDecimal("3")) > 0) {
                zhaiFlag = true;
                break;
            }
            for (int i = 0; i < item.getQuantity(); i++) {
                less30List.add(new ProductMemoMsg(item.getSku(), item.getProductId(), sizeB.getLength(), sizeB.getWidth(),
                        sizeB.getHeight(), sizeB.getWeight(), sizeB.getLengthBs(), sizeB.getWidthBs(), sizeB.getHeightBs(), sizeB.getWeightBs(),sizeB.getMinSize()));
            }
        }
        if (!zhaiFlag) {
            this.sort(less30List);
            this.packProducts(packageList, less30List);
        }
        return new OrderPackageRes(packageList, zhaiFlag);
    }

    public void getPackage(List<List<ProductMemoMsg>> packageList, List<ProductMemoMsg> less30List) {
        if (CollUtil.isEmpty(less30List)) {
            return;
        }
        List<ProductMemoMsg> list = new ArrayList<>();
        BigDecimal sizeBig = new BigDecimal(0);
        for (int i = 0; i < less30List.size(); i++) {
            ProductMemoMsg et = less30List.get(i);
            BigDecimal itemMemo = et.getItemMemo();
            if (itemMemo.compareTo(new BigDecimal("3")) > 0) {
                packageList.add(Collections.singletonList(et));
                less30List.remove(i);
                i--;
                continue;
            }
            BigDecimal add = sizeBig.add(itemMemo);
            if (add.compareTo(new BigDecimal("3")) > 0) {
                //大于
                break;
            } else {
                sizeBig = add;
                list.add(et);
                less30List.remove(i);
                i--;
            }
        }
        packageList.add(list);
        if (!CollUtil.isEmpty(less30List)) {
            this.getPackage(packageList, less30List);
        }
    }


    // 定义常量，避免重复创建BigDecimal对象
    private static final BigDecimal THREE = new BigDecimal("3");
    private static final BigDecimal ZERO = new BigDecimal("0");

    /**
     * 将产品按规则分组打包
     * @param resultPackages 最终的包裹列表
     * @param remainingProducts 待处理的产品列表
     */
    public void packProducts(List<List<ProductMemoMsg>> resultPackages, List<ProductMemoMsg> remainingProducts) {
        // 空列表直接返回，避免无效处理
        if (remainingProducts == null || remainingProducts.isEmpty()) {
            return;
        }

        List<ProductMemoMsg> currentPackage = new ArrayList<>();
        BigDecimal currentSize = ZERO;
        Iterator<ProductMemoMsg> iterator = remainingProducts.iterator();

        while (iterator.hasNext()) {
            ProductMemoMsg product = iterator.next();
            BigDecimal productSize = product.getItemMemo();

            // 处理null值，避免空指针异常
            if (productSize == null) {
                productSize = ZERO;
            }

            // 大于3的产品单独成包
            if (productSize.compareTo(THREE) > 0) {
                resultPackages.add(Collections.singletonList(product));
                iterator.remove(); // 使用迭代器安全移除
                continue;
            }

            // 尝试加入当前包裹
            BigDecimal newSize = currentSize.add(productSize);
            if (newSize.compareTo(THREE) <= 0) {
                // 可以加入当前包裹
                currentPackage.add(product);
                currentSize = newSize;
                iterator.remove();
            } else {
                // 当前包裹已满，不再继续添加
                break;
            }
        }

        // 将当前包裹加入结果（如果不为空）
        if (!currentPackage.isEmpty()) {
            resultPackages.add(currentPackage);
        }

        // 递归处理剩余产品（如果还有）
        if (!remainingProducts.isEmpty()) {
            packProducts(resultPackages, remainingProducts);
        }
    }

    public void sort(List<ProductMemoMsg> list) {
        list.sort(
                (o1, o2) -> {
                    if (o1.getItemMemo().compareTo(o2.getItemMemo()) == 0) {
                        return o1.getProductSkuCode().compareTo(o2.getProductSkuCode());
                    } else if (o1.getItemMemo().compareTo(o2.getItemMemo()) > 0) {
                        return -1;
                    } else {
                        return 1;
                    }
                }
        );
    }

    public void setSizeArr(Double[] sizeCm, double length, double width, double height, double weight, int quantity) {
        double[] productSize = new double[]{length, width, height};
        Arrays.sort(productSize);//从小到大
        sizeCm[0] = sizeCm[0] + productSize[0] * quantity;
        sizeCm[1] = sizeCm[1] + productSize[1];
        sizeCm[2] = sizeCm[2] + productSize[2];
        sizeCm[3] = sizeCm[3] + weight * quantity;
    }

    public void getSize(Double length, Double width, Double height, Double weight, Double[] size) {
        Double[] productSize = new Double[]{length, width, height};
        Arrays.sort(productSize);
        size[0] = productSize[0];
        size[1] = productSize[1];
        size[2] = productSize[2];
        size[3] = weight;
    }

    /**
     * 体积重计算模式三边和
     */
    public void getLogBaseFeeForTrilateralSum(Map<String, List<SurchargeFeeRes>> zoneSurMap, List<FreightTempWeightDo> weightDoList, List<String> zones, QsItemDetailVoVo item, Double[] size) {
        Long weightId = null;
        double weight = size[3];
        double volumeW = size[5];
        double calWeight = weight;
        for (FreightTempWeightDo weightDo : weightDoList) {
            //三边和 需要验证重量和体积重 不计算只要验证重量 体积重/体积重系数应该只要验证 重量，但是计费重量 = 重量 和体积重最大值
            //三边和没有续重价 和 单价模式
            if ((weightDo.getEndWeight() < weight)) continue;
            if ((weightDo.getEndVolumeWeight() < volumeW)) continue;
            //满足 条件
            weightId = weightDo.getId();
            //算出计费重  如果体积重在重量段范围 则结束段是计费重
            if (weightDo.getStartWeight() < volumeW) {
                calWeight = weightDo.getEndWeight();
            }
            break;
        }
        size[4] = calWeight;//计费重
        //三边和没有续重价 和 单价模式
        if (weightId == null) {
            //重量段不满足 就是没有费用
            for (String zone : zones) {
                zoneSurMap.computeIfAbsent(zone, k -> new ArrayList<>()).add(new SurchargeFeeRes("基础运费", 0d));
            }
        } else {
            //匹配重量段
            List<FreightTempZonePriceDo> priceDos = freightTempZonePriceDao.selectList(new LambdaQueryWrapper<FreightTempZonePriceDo>()
                    .in(FreightTempZonePriceDo::getFreightTempWeightId, weightId)
                    .in(FreightTempZonePriceDo::getZone, zones)
                    .eq(FreightTempZonePriceDo::getPriceType, "freight"));
            //去获取重量段 对应分区价格
            for (FreightTempZonePriceDo priceDo : priceDos) {
                // 物流费运费可以加减乘
                double zonePrice = priceDo.getZonePrice();
                if (item.getAdjustmentStatus() == 1) {
                    if (item.getAdjustmentType() == 0) {
                        zonePrice += item.getAdjustmentPrice();
                    } else if (item.getAdjustmentType() == 1) {
                        zonePrice -= item.getAdjustmentPrice();
                    } else {
                        //乘法最后乘 加减 每一档重量都需要加减
                        zonePrice = zonePrice * item.getAdjustmentPrice();
                    }
                }
                SurchargeFeeRes surchargeFeeRes = new SurchargeFeeRes("基础运费", zonePrice);
                zoneSurMap.computeIfAbsent(priceDo.getZone(), k -> new ArrayList<>()).add(surchargeFeeRes);
            }
        }
    }

    /**
     * 体积重计算方式：不计算 或者 体积/体积重系数
     */
    public void getLogBaseFeeNoVolume(Map<String, List<SurchargeFeeRes>> zoneSurMap, List<FreightTempWeightDo> weightDoList, List<String> zones, QsItemDetailVoVo item, Double[] size) {
        Map<Integer, List<FreightTempWeightDo>> continueMap = weightDoList.stream().collect(Collectors.groupingBy(FreightTempWeightDo::getContinueWeight));
        double weight = size[4];//计费重
        Long weightId = null;
        for (FreightTempWeightDo weightDo : continueMap.get(0)) {//0 总价
            //三边和 需要验证重量和体积重 不计算只要验证重量 体积重/体积重系数应该只要验证 重量，但是计费重量 = 重量 和体积重最大值
            //三边和没有续重价 和 单价模式
            //体积重 不计算模式 只比较体重
            if ((weightDo.getEndWeight() < weight)) continue;
            //满足 条件
            weightId = weightDo.getId();
            break;
        }
        Map<Long, Double> xuZhoWeightMap = new HashMap<>();//续重价 记录续重挡位的重量
        boolean danJia = false;
        if (weightId == null) {
            //看看续重价 或者 区间是否满足
            if (continueMap.get(1) != null) {
                //续重价 需要加上  每个挡位的钱*重量
                for (int i = 0; i < continueMap.get(1).size(); i++) {
                    FreightTempWeightDo weightDo = continueMap.get(1).get(i);
                    if ((weightDo.getEndWeight() < weight)) {
                        continue;
                    }
                    //满足条件
                    for (int j = 0; j <= i; j++) {
                        FreightTempWeightDo xuWeightDo = continueMap.get(1).get(j);
                        if (j < i) {
                            xuZhoWeightMap.put(xuWeightDo.getId(), xuWeightDo.getEndWeight() - xuWeightDo.getStartWeight());
                        } else {
                            //最后一个用计费重 - 开始
                            xuZhoWeightMap.put(xuWeightDo.getId(), weight - xuWeightDo.getStartWeight());
                        }
                    }
                    weightId = continueMap.get(0).get(continueMap.get(0).size() - 1).getId();
                    break;
                }
            } else if (continueMap.get(2) != null) {
                //单价 匹配上 就用该段位价格 * 重量 就行，调整费用也是
                for (int i = 0; i < continueMap.get(2).size(); i++) {
                    FreightTempWeightDo weightDo = continueMap.get(1).get(i);
                    if (!(weightDo.getStartWeight() > weight && weightDo.getEndWeight() <= weight)) {
                        continue;
                    }
                    weightId = weightDo.getId();//这里直接赋值 单价重量段id
                    danJia = true;
                    break;
                }
            }
        }

        if (weightId == null) {
            //重量段不满足 就是没有费用
            for (String zone : zones) {
                SurchargeFeeRes surchargeFeeRes = new SurchargeFeeRes("基础运费", 0d);
                zoneSurMap.computeIfAbsent(zone, k -> new ArrayList<>()).add(surchargeFeeRes);
            }
        } else {
            //匹配重量段
            List<FreightTempZonePriceDo> priceDos = freightTempZonePriceDao.selectList(new LambdaQueryWrapper<FreightTempZonePriceDo>()
                    .in(FreightTempZonePriceDo::getFreightTempWeightId, weightId)
                    .in(FreightTempZonePriceDo::getZone, zones)
                    .eq(FreightTempZonePriceDo::getPriceType, "freight"));

            Map<String, List<FreightTempZonePriceDo>> xuZhoPriceMap = new HashMap<>();
            if (!xuZhoWeightMap.isEmpty()) {
                List<FreightTempZonePriceDo> xuZhoPriceDos = freightTempZonePriceDao.selectList(new LambdaQueryWrapper<FreightTempZonePriceDo>()
                        .in(FreightTempZonePriceDo::getFreightTempWeightId, xuZhoWeightMap.keySet())
                        .in(FreightTempZonePriceDo::getZone, zones)
                        .eq(FreightTempZonePriceDo::getPriceType, "freight"));
                xuZhoPriceMap = xuZhoPriceDos.stream().collect(Collectors.groupingBy(FreightTempZonePriceDo::getZone));
            }

            //去获取重量段 对应分区价格
            for (FreightTempZonePriceDo priceDo : priceDos) {
                double xuZhoFee = 0d;
                if (xuZhoPriceMap.get(priceDo.getZone()) != null) {
                    //一个分区可能匹配多个续重价格
                    for (FreightTempZonePriceDo freightTempZonePriceDo : xuZhoPriceMap.get(priceDo.getZone())) {
                        //续重 = 续重单位 * 区间重量
                        xuZhoFee += freightTempZonePriceDo.getZonePrice() * xuZhoWeightMap.get(freightTempZonePriceDo.getFreightTempWeightId());
                    }
                }
                double price;
                if (danJia) {
                    //单价模式 = 重量段价格 * 计费重
                    price = priceDo.getZonePrice() * weight;
                    if (item.getAdjustmentStatus() == 1) {
                        if (item.getAdjustmentType() == 0) {
                            price += weight * item.getAdjustmentPrice();
                        } else if (item.getAdjustmentType() == 1) {
                            price -= weight * item.getAdjustmentPrice();
                        } else {
                            //乘法最后乘 加减 每一档重量都需要加减
                            price = price * item.getAdjustmentPrice();
                        }
                    }
                } else {
                    price = xuZhoFee + priceDo.getZonePrice();
                    //续重模式
                    if (item.getAdjustmentStatus() == 1) {
                        double w = xuZhoWeightMap.values().stream().mapToDouble(Double::doubleValue).sum() + 1;
                        if (item.getAdjustmentType() == 0) {
                            price += w * item.getAdjustmentPrice();
                        } else if (item.getAdjustmentType() == 1) {
                            price -= w * item.getAdjustmentPrice();
                        } else {
                            //乘法最后乘 加减 每一档重量都需要加减
                            price = price * item.getAdjustmentPrice();
                        }
                    }
                }
                //物流费运费可以加减乘
                SurchargeFeeRes surchargeFeeRes = new SurchargeFeeRes("基础运费", price);
                zoneSurMap.computeIfAbsent(priceDo.getZone(), k -> new ArrayList<>()).add(surchargeFeeRes);
            }
        }
    }

    public boolean jugByCalType(int calType, int operateSign, Double startValue, Double endValue, Double[] sizeCm) {
        boolean flag = true;
        if (StaticDict.Channel_Calculate_Type.Longest_Side.getValue().equals(calType)) { //最长边
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[2]);
        } else if (StaticDict.Channel_Calculate_Type.Second_Longest_Side.getValue().equals(calType)) {
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[1]);
        } else if (StaticDict.Channel_Calculate_Type.Shortest_Size.getValue().equals(calType)) {
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[0]);
        } else if (StaticDict.Channel_Calculate_Type.Fourth.getValue().equals(calType)) {//最长边+2*(次长边+最短边)
            double size = sizeCm[2] + 2 * (sizeCm[0] + sizeCm[1]);
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, size);
        } else if (StaticDict.Channel_Calculate_Type.Volume_Weight.getValue().equals(calType)) {//体积重
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[5]);
        } else if (StaticDict.Channel_Calculate_Type.Billing_Weight.getValue().equals(calType)) {//计费重
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[4]);
        }
        //这里是附加费-超长超重的规则
        else if (StaticDict.Sc_Calculate_Type.ThreeSize.getValue().equals(calType)) {//三边之和
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[0] + sizeCm[1] + sizeCm[2]);
        } else if (StaticDict.Sc_Calculate_Type.ActualWeight.getValue().equals(calType)) {//实重
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[3]);
        } else if (StaticDict.Sc_Calculate_Type.Volume.getValue().equals(calType)) {//体积 CBM 立方米 CBF立方英尺  //1立方英尺CBF = 1728 英寸 1立方米CBM = 1000000厘米
            flag = this.jugLcRuleSize(operateSign, startValue, endValue, sizeCm[6]);
        } else {
            flag = false;
        }
        return flag;
    }

    /**
     * 判断物流渠道下单规则
     *
     * @param size
     * @return
     */
    public boolean jugLcRuleSize(int operateSign, Double startValue, Double endValue, Double size) {
        boolean flag = true;
        if (size == null) return true;
        if (StaticDict.Rule_Operate_Sign.Less_Than.getValue().equals(operateSign)) {  //小于
            if (size >= startValue) {
                //不满足条件
                flag = false;
            }
        } else if (StaticDict.Rule_Operate_Sign.Greater_Equal.getValue().equals(operateSign)) {//大于等于
            if (size < startValue) {
                //不满足条件
                flag = false;
            }
        } else if (StaticDict.Rule_Operate_Sign.Less_Equal.getValue().equals(operateSign)) {//小于等于
            if (size > startValue) {
                //不满足条件
                flag = false;
            }
        } else if (StaticDict.Rule_Operate_Sign.Between.getValue().equals(operateSign)) {//介于
            if (size < startValue || size > endValue) {
                //不满足条件
                flag = false;
            }
        } else if (StaticDict.Rule_Operate_Sign.Equal.getValue().equals(operateSign)) {//等于
            if (!size.equals(startValue)) {
                //不满足条件
                flag = false;
            }
        } else if (StaticDict.Rule_Operate_Sign.Greater_Than.getValue().equals(operateSign)) {//大于
            if (size <= startValue) {
                //不满足条件
                flag = false;
            }
        }
        return flag;
    }

    public Long getQsId(Long companyId, Long whId) {
        QuotationSchemeDo qsDo = dao.getQsByCompanyId(companyId, whId);
        return qsDo == null ? null : qsDo.getId();
    }

    //计算操作费-退件单
    @Override
    public void costAddReturn(CostAddEt costAddEt, List<OrProductPageDto> orProductPageDtos, Long tenantId) {
//        WarehouseDo warehouseDo = warehouseService.getById(costAddEt.getWhId());
        OrderMsgForCostEt orderMsg = new OrderMsgForCostEt();
        orderMsg.setSkuKind((int) orProductPageDtos.stream().map(OrProductPageDto::getProductId).distinct().count());
        List<SkuMsg> skus = new ArrayList<>();
        for (OrProductPageDto product : orProductPageDtos) {
            Size size = BeanConvert.INSTANCE.size(product);
            skus.add(SkuMsg.builder()
                    .qty(product.getPutawayGoodQty() + product.getPutawayBadQty()).size(size).build());
        }
        OrderReturnDo et = orderReturnService.getById(costAddEt.getOrderId());
        List<OrPackDetailRes> packDetail = orderReturnService.getPackDetail(costAddEt.getOrderId(), et.getSizeUnit(), et.getWmsSizeUnit());
        List<BoxMsg> boxes = new ArrayList<>();
        for (OrPackDetailRes pack : packDetail) {
            if (pack.getReach() == 0) continue;
            if (pack.getLengthW() == null) {
                boxes.add(new BoxMsg(1,
                        new Size(BigDecimal.valueOf(pack.getHeight()), BigDecimal.valueOf(pack.getHeightBs()), BigDecimal.valueOf(pack.getLength()),
                                BigDecimal.valueOf(pack.getLengthBs()), BigDecimal.valueOf(pack.getWidth()), BigDecimal.valueOf(pack.getWidthBs()),
                                BigDecimal.valueOf(pack.getWeight()), BigDecimal.valueOf(pack.getWeightBs()))
                        , pack.getTrackNo()));
            } else {
                boxes.add(new BoxMsg(1,
                        new Size(BigDecimal.valueOf(pack.getHeightW()), BigDecimal.valueOf(pack.getHeightW_bs()), BigDecimal.valueOf(pack.getLengthW()),
                                BigDecimal.valueOf(pack.getLengthW_bs()), BigDecimal.valueOf(pack.getWidthW()), BigDecimal.valueOf(pack.getWidthW_bs()),
                                BigDecimal.valueOf(pack.getWeightW()), BigDecimal.valueOf(pack.getWeightW_bs()))
                        , pack.getTrackNo()));
            }
        }
        orderMsg.setBoxes(boxes);
        orderMsg.setSkus(skus);
        orderMsg.setOrderType(StaticDict.Cost_Input_OrderType.Fourth.getValue());
        this.setTotalWeight(orderMsg);
        CostInfoEntity costEntity = this.getCostInfo(costAddEt, orderMsg);
        costEntity.setStatus(0);
        costService.insertEntity(costEntity, null);
    }

    /**
     * 计算操作费 - 入库单
     *
     * @param req
     */
    @Override
    public void costAddInput(OrderInputCostReq req) {
        CostAddEt costAddEt = new CostAddEt(req.getStatus(), req.getOrderNo(), req.getOrderId(), req.getWhId(), req.getCompanyId(), req.getTenantId(), req.getOmsOrderCreateTime());
        costAddEt.setModuleType(StaticDict.Cost_ModuleType.First.getValue());
        costAddEt.setOrderType(req.getOrderType());
        OrderMsgForCostEt orderMsg = new OrderMsgForCostEt(req.getBoxes(), req.getSkus());
        this.setTotalWeight(orderMsg);
        CostInfoEntity costEntity = this.getCostInfo(costAddEt, orderMsg);
        costService.insertEntity(costEntity, null);

    }

    public CostInfoEntity getCostInfo(CostAddEt costAddEt, OrderMsgForCostEt orderMsg) {
        Long tenantId = costAddEt.getTenantId();
        WarehouseDo warehouseDo = warehouseService.getById(costAddEt.getWhId());
        QuotationSchemeDo qsId = dao.getQsByCompanyId(costAddEt.getCompanyId(), costAddEt.getWhId());
        CostInfoEntity costDo = BeanConvert.INSTANCE.costInfoEntity(costAddEt);

        costDo.setCurrencyCode(warehouseDo.getCurrencyCode());
        List<CostItemEt> costItemEtList = new ArrayList<>();
        if (qsId == null) {
            costDo.setCostStatus(1);
        } else {
            costDo.setQuotationId(qsId.getId());
            costDo.setCostStatus(2);
            costDo.setCostTime(new Date());
            //获取报价的 入库 操作费
            List<QsItemDetailVoVo> list = quotationItemDao.list(qsId.getId(), costAddEt.getWhId(), tenantId, 1);
            Map<Long, QsItemDetailVoVo> qsItemMap = list.stream().collect(Collectors.toMap(QsItemDetailVoVo::getThirdId, i -> i));
            //根据操作费 获取 操作费详情
//            double operateFee = 0d;
            if (!qsItemMap.isEmpty()) {
                List<Integer> billTypeList = new ArrayList<>();
                if (StaticDict.Cost_Input_OrderType.First.getValue().equals(costAddEt.getOrderType())) {
                    //101,201
                    billTypeList.add(StaticDict.OperateBill_Type.Input_One.getValue());
                    billTypeList.add(StaticDict.OperateBill_Type.Input_Two.getValue());
                    billTypeList.add(StaticDict.OperateBill_Type.Input_Three.getValue());
                } else if (StaticDict.Cost_Input_OrderType.Second.getValue().equals(costAddEt.getOrderType())) {
                    billTypeList.add(StaticDict.OperateBill_Type.Input_One.getValue());
                    billTypeList.add(StaticDict.OperateBill_Type.Input_Two.getValue());
                } else if (StaticDict.Cost_Input_OrderType.Third.getValue().equals(costAddEt.getOrderType())) {
                    billTypeList.add(StaticDict.OperateBill_Type.Input_One.getValue());
                    billTypeList.add(StaticDict.OperateBill_Type.Input_Three.getValue());
                } else {
                    billTypeList.add(Integer.parseInt(costAddEt.getOrderType()));
                }
                List<OperateBillDo> operateBillDos = operateBillDao.selectList(new LambdaQueryWrapper<OperateBillDo>()
                        .in(OperateBillDo::getBillType, billTypeList) //这里我将操作费的 billType 和 cost 的orderType 统一了
                        .in(OperateBillDo::getId, qsItemMap.keySet()).eq(OperateBillDo::getTenantId, tenantId));
                Map<Long, List<OperateBillRuleDo>> ruleMap = operateBillRuleDao.selectList(new LambdaQueryWrapper<OperateBillRuleDo>().in(OperateBillRuleDo::getOperateBillId, qsItemMap.keySet())).stream().collect(Collectors.groupingBy(OperateBillRuleDo::getOperateBillId));
                Map<Long, List<OperateBillRuleConditionDo>> conditionMap = operateBillRuleConditionDao.selectList(new LambdaQueryWrapper<OperateBillRuleConditionDo>().in(OperateBillRuleConditionDo::getOperateBillId, qsItemMap.keySet())).stream().collect(Collectors.groupingBy(OperateBillRuleConditionDo::getRuleId));
                Map<Long, List<OperateBillChannelDo>> billChannelMap = operateBillChannelDao.selectList(new LambdaQueryWrapper<OperateBillChannelDo>()
                        .in(OperateBillChannelDo::getOperateBillId, qsItemMap.keySet())).stream().collect(Collectors.groupingBy(OperateBillChannelDo::getOperateBillId));
                double totalFee = 0d;
                for (OperateBillDo operateBillDo : operateBillDos) {
                    //操作费 如果是出库操作费 还要判断 出库操作费的物流渠道 包含本次物流渠道吗
                    if (StaticDict.Cost_Out_OrderType.First.getValue().equals(costAddEt.getOrderType())
                            ||StaticDict.Cost_Out_OrderType.DiaoBo.getValue().equals(costAddEt.getOrderType())
                            || StaticDict.Cost_Out_OrderType.Second.getValue().equals(costAddEt.getOrderType())) {
                        //出库类型
                        List<OperateBillChannelDo> billChanList = billChannelMap.get(operateBillDo.getId());
                        if (billChanList == null || billChanList.isEmpty()) continue;
                        if (!billChanList.stream().map(OperateBillChannelDo::getChannelId).collect(Collectors.toList()).contains(orderMsg.getTrackId()))
                            continue;
                    }

                    List<OperateBillRuleDo> rules = ruleMap.get(operateBillDo.getId());//里面有单价 计费变量 等等
                    if (rules == null) continue;
                    //通过 rule 剔除 不符合收费的sku box
                    List<BoxMsg> chargeBoxes = orderMsg.getBoxes();
                    List<SkuMsg> chargeSkus = orderMsg.getSkus();

                    Map<Long, String> ruleExplainMap = operateBillService.getRuleExplainMap(rules, conditionMap, operateBillDo.getCurrencyCode());
                    StringBuilder ruleExplain = new StringBuilder();
                    double oneOpeFee = 0d;
                    for (OperateBillRuleDo rule : rules) {//操作费里的收费项
                        List<OperateBillRuleConditionDo> conditionDos = conditionMap.get(rule.getId());
                        if (conditionDos == null) continue;
                        //判断条件是否满足
                        boolean flag = true;
                        for (OperateBillRuleConditionDo conditionDo : conditionDos) { //退件不支持  箱子数量 单箱重量 单箱体积
                            //条件变量 sku种类 箱子数量 单箱重量 单箱体积 单个sku重量 票体积 票总重
                            if (StaticDict.OperateBill_ConditionCode.First.getValue().equals(conditionDo.getConditionCode())) { //Sku种类
                                if (conditionDo.getSetWay() == 0) {//区间 左开右闭
                                    flag = orderMsg.getSkuKind() > Integer.parseInt(conditionDo.getStartVariable()) && orderMsg.getSkuKind() <= Integer.parseInt(conditionDo.getEndVariable());
                                } else {//单边
                                    flag = this.jugLcRuleSize(Integer.parseInt(conditionDo.getStartVariable()), Double.parseDouble(conditionDo.getEndVariable()), null, (double) orderMsg.getSkuKind());
                                }
                            } else if (StaticDict.OperateBill_ConditionCode.Return_Pack_Count.getValue().equals(conditionDo.getConditionCode()) ||
                                    StaticDict.OperateBill_ConditionCode.Second.getValue().equals(conditionDo.getConditionCode())) {
                                //包裹数量 //箱子数量
                                if (conditionDo.getSetWay() == 0) {//区间 左开右闭
                                    flag = orderMsg.getBoxQty() > Integer.parseInt(conditionDo.getStartVariable()) && orderMsg.getSkuKind() <= Integer.parseInt(conditionDo.getEndVariable());
                                } else {//单边
                                    flag = this.jugLcRuleSize(Integer.parseInt(conditionDo.getStartVariable()), Double.parseDouble(conditionDo.getEndVariable()), null, (double) orderMsg.getBoxQty());
                                }
                            } else if (StaticDict.OperateBill_ConditionCode.Return_Pack_SizeSum.getValue().equals(conditionDo.getConditionCode())) {
                                //包裹三边和
                                for (int i = 0; i < chargeBoxes.size(); i++) {
                                    BoxMsg box = chargeBoxes.get(i);
                                    double sizeSum = this.getSizeSum(operateBillDo, box);
                                    i = removeBox(chargeBoxes, conditionDo, i, sizeSum);
                                }
                                if (chargeBoxes.isEmpty()) flag = false;
                            } else if (StaticDict.OperateBill_ConditionCode.Third.getValue().equals(conditionDo.getConditionCode())) {//单箱重量
                                for (int i = 0; i < chargeBoxes.size(); i++) {
                                    BoxMsg box = chargeBoxes.get(i);
                                    double weight = this.getWeight(operateBillDo.getWeightUnit(), operateBillDo.getWeightCalculateWay(), operateBillDo.getCoefficient(), box.getSize());
                                    i = removeBox(chargeBoxes, conditionDo, i, weight);
                                }
                                if (chargeBoxes.isEmpty()) flag = false;
                            } else if (StaticDict.OperateBill_ConditionCode.Fourth.getValue().equals(conditionDo.getConditionCode())) {//单箱体积
                                for (int i = 0; i < chargeBoxes.size(); i++) {
                                    BoxMsg box = chargeBoxes.get(i);
                                    double volume = this.getVolume(operateBillDo.getVolumeUnit(), box.getSize());
                                    i = removeBox(chargeBoxes, conditionDo, i, volume);
                                }
                                if (chargeBoxes.isEmpty()) flag = false;
                            } else if (StaticDict.OperateBill_ConditionCode.Fifth.getValue().equals(conditionDo.getConditionCode())) {//单个SKU重量
                                //支持 sku数量 单种sku数量   (*单个sku重量)
                                for (int i = 0; i < chargeSkus.size(); i++) {
                                    SkuMsg sku = chargeSkus.get(i);
                                    double weight = this.getWeight(operateBillDo.getWeightUnit(), operateBillDo.getWeightCalculateWay(), operateBillDo.getCoefficient(), sku.getSize());
                                    boolean cFlag;
                                    if (conditionDo.getSetWay() == 0) {//区间 左开右闭 附加费那边是两边都是闭合
                                        cFlag = weight > Integer.parseInt(conditionDo.getStartVariable()) && weight <= Integer.parseInt(conditionDo.getEndVariable());
                                    } else {
                                        cFlag = this.jugLcRuleSize(Integer.parseInt(conditionDo.getStartVariable()), Double.parseDouble(conditionDo.getEndVariable()), null, weight);
                                    }
                                    if (!cFlag) {//不满足
                                        chargeSkus.remove(i);
                                        i--;
                                    }
                                }
                                if (chargeSkus.isEmpty()) flag = false;
                            } else if (StaticDict.OperateBill_ConditionCode.Sixth.getValue().equals(conditionDo.getConditionCode())) {//票体积
                                //计算票体积 票重量
                                double totalVolume = StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(operateBillDo.getVolumeUnit()) ? orderMsg.getTotalVolume().getValue().doubleValue()
                                        : orderMsg.getTotalVolume().getValueBs().doubleValue();
                                if (conditionDo.getSetWay() == 0) {//区间 左开右闭 附加费那边是两边都是闭合
                                    flag = totalVolume > Integer.parseInt(conditionDo.getStartVariable()) && totalVolume <= Integer.parseInt(conditionDo.getEndVariable());
                                } else {
                                    flag = this.jugLcRuleSize(Integer.parseInt(conditionDo.getStartVariable()), Double.parseDouble(conditionDo.getEndVariable()), null, totalVolume);
                                }
                            } else if (StaticDict.OperateBill_ConditionCode.Seventh.getValue().equals(conditionDo.getConditionCode())) {//票总重
                                double totalVolume = StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(operateBillDo.getWeightUnit()) ? orderMsg.getTotalWeight().getValue().doubleValue() : orderMsg.getTotalWeight().getValueBs().doubleValue();
                                if (conditionDo.getSetWay() == 0) {//区间 左开右闭 附加费那边是两边都是闭合
                                    flag = totalVolume > Integer.parseInt(conditionDo.getStartVariable()) && totalVolume <= Integer.parseInt(conditionDo.getEndVariable());
                                } else {
                                    flag = this.jugLcRuleSize(Integer.parseInt(conditionDo.getStartVariable()), Double.parseDouble(conditionDo.getEndVariable()), null, totalVolume);
                                }
                            }
                        }

                        if (!flag) break;
                        //满足条件 这一计费变量 开始计费
                        //判断报价有没有调整基础价格
                        OrderMsgForCostEt newMsg = new OrderMsgForCostEt();
                        newMsg.setOrderType(orderMsg.getOrderType());
                        newMsg.setBoxes(chargeBoxes);
                        newMsg.setSkus(chargeSkus);
                        //更新sku种类什么的
                        this.setTotalWeight(newMsg);

                        double unitPrice = this.getUnitPrice(rule.getUnitPrice(), qsItemMap.get(operateBillDo.getId()));
                        double calCount = 0d; //减免量 先减 在除以单位数量
                        if (StaticDict.OperateBill_CalCode.Code08.getValue().equals(rule.getBillCode())) {//单个SKU重量
                            for (SkuMsg sku : chargeSkus) {
                                double weight = this.getWeight(operateBillDo.getWeightUnit(), operateBillDo.getWeightCalculateWay(), operateBillDo.getCoefficient(), sku.getSize());
                                calCount += weight * sku.getQty();
                            }
                            calCount = Math.max(calCount - rule.getRelieQtyZ(), 0);
                        } else if (StaticDict.OperateBill_CalCode.Code02.getValue().equals(rule.getBillCode())) {//sku种类
                            calCount = Math.max(newMsg.getSkuKind() - rule.getRelieQtyZ(), 0);
                        } else if (StaticDict.OperateBill_CalCode.Code01.getValue().equals(rule.getBillCode())) {//票
                            calCount = 1;
                        } else if (StaticDict.OperateBill_CalCode.Code11.getValue().equals(rule.getBillCode())) {//票总重
                            double totalWeight = getTotalWeight(newMsg, operateBillDo, rule);
                            calCount = Math.max(totalWeight - rule.getRelieQtyZ(), 0);
                        } else if (StaticDict.OperateBill_CalCode.Return_Pack_Count.getValue().equals(rule.getBillCode()) ||
                                StaticDict.OperateBill_CalCode.Code03.getValue().equals(rule.getBillCode())) {//包裹数量 //箱子数量
                            calCount = Math.max(newMsg.getBoxQty() - rule.getRelieQtyZ(), 0);
                        } else if (StaticDict.OperateBill_CalCode.Code04.getValue().equals(rule.getBillCode())) {//单箱重量
                            for (BoxMsg box : chargeBoxes) {
                                double weight = this.getWeight(operateBillDo.getWeightUnit(), operateBillDo.getWeightCalculateWay(), operateBillDo.getCoefficient(), box.getSize());
                                calCount += weight;
                            }
                            calCount = Math.max(calCount - rule.getRelieQtyZ(), 0);
                        } else if (StaticDict.OperateBill_CalCode.Code05.getValue().equals(rule.getBillCode())) {//单箱体积
                            for (BoxMsg box : chargeBoxes) {
                                double volume = this.getVolume(operateBillDo.getVolumeUnit(), box.getSize());
                                calCount += volume;
                            }
                            calCount = Math.max(calCount - rule.getRelieQtyZ(), 0);
                        }
//                        StringBuilder feeCalDetail = new StringBuilder();
                        double fee = 0d;
                        if (rule.getBaseFee() != null) {
                            fee += rule.getBaseFee();
//                            feeCalDetail.append("$").append(rule.getBaseFee());
                        }
                        calCount = calCount / rule.getUnitQty();//除以单位数量
                        if (rule.getUnitCarry() == 1) {//进位
                            calCount = Math.ceil(calCount);
                        }
                        fee += calCount * unitPrice;
//                        feeCalDetail.append(calCount).append("*$").append(unitPrice);
                        if (rule.getLowestFee() != null) {
                            fee = Math.max(fee, rule.getLowestFee());
                        }
                        if (rule.getHighestFee() != null) {
                            fee = Math.min(fee, rule.getHighestFee());
                        }
                        oneOpeFee += fee;
                        if (ruleExplain.length() > 0) {
                            ruleExplain.append(";");
                        }
                        ruleExplain.append(ruleExplainMap.get(rule.getId()));
                    }
                    if (oneOpeFee > 0) {

                        costItemEtList.add(new CostItemEt(operateBillDo.getBillItemName(), operateBillDo.getBillType(), ruleExplain.toString(), oneOpeFee)); //todo 计费详情
                        totalFee += oneOpeFee;
                    }

                }
                costDo.setCostTotal(new BigDecimal(totalFee));

            }
        }
        costDo.setItems(costItemEtList);
        return costDo;
    }

    private int removeBox(List<BoxMsg> chargeBoxes, OperateBillRuleConditionDo conditionDo, int i, double weight) {
        boolean cFlag;
        if (conditionDo.getSetWay() == 0) {//区间 左开右闭
            cFlag = weight > Double.parseDouble(conditionDo.getStartVariable()) && weight <= Double.parseDouble(conditionDo.getEndVariable());
        } else {//单边
            cFlag = this.jugLcRuleSize(Integer.parseInt(conditionDo.getStartVariable()), Double.parseDouble(conditionDo.getEndVariable()), null, weight);
        }
        if (!cFlag) {//不满足
            chargeBoxes.remove(i);
            i--;
        }
        return i;
    }

    private double getSizeSum(OperateBillDo operateBillDo, BoxMsg box) {
        double sizeSum;
        if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(operateBillDo.getWeightUnit())) {
            sizeSum = box.getSize().getLength().doubleValue() + box.getSize().getWidth().doubleValue() + box.getSize().getHeight().doubleValue();
        } else {
            sizeSum = box.getSize().getLengthBs().doubleValue() + box.getSize().getWidthBs().doubleValue() + box.getSize().getHeightBs().doubleValue();
        }
        return sizeSum;
    }

    public double getUnitPrice(double price, QsItemUtilEtVo qsItem) {
        if (qsItem == null || qsItem.getAdjustmentStatus() == 0) return price;
        if (qsItem.getAdjustmentType() == 0) {
            price += qsItem.getAdjustmentPrice();
        } else if (qsItem.getAdjustmentType() == 1) {
            price -= qsItem.getAdjustmentPrice();
        } else if (qsItem.getAdjustmentType() == 2) {
            price = price * qsItem.getAdjustmentPrice() / 100;
        }
        return price;
    }


    private double getWeight(String weightUnit, Integer weightCalculateWay, Integer coe, Size size) {
        double weight;
        if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(weightUnit)) {
            //公制
            weight = size.getWeight().doubleValue();
            if (weightCalculateWay == 1) {
                //体积重和实重最大值
                weight = Math.max(weight, size.getLength().doubleValue() * size.getWidth().doubleValue() * size.getHeight().doubleValue() / coe);
            }
        } else {
            //英制
            weight = size.getWeightBs().doubleValue();
            if (weightCalculateWay == 1) {
                //体积重和实重最大值
                weight = Math.max(weight, size.getLengthBs().doubleValue() * size.getWidthBs().doubleValue() * size.getHeightBs().doubleValue() / coe);
            }
        }
        return weight;
    }


    private double getVolume(String weightUnit, Size size) {
        double weight;
        if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(weightUnit)) {
            //公制
            weight = size.getLength().doubleValue() * size.getWidth().doubleValue() * size.getHeight().doubleValue();
        } else {
            //英制
            weight = size.getLengthBs().doubleValue() * size.getWidthBs().doubleValue() * size.getHeightBs().doubleValue();
        }
        return weight;
    }


    /**
     * 计算操作费 出库单
     */
    @Override
    public TrialFreightRes costAddOut(OrderOutCostReq req) {
        TrialOmsReq trialReq = BeanConvert.INSTANCE.trialOmsReq(req);
        CostAddEt addEt = new CostAddEt(req.getStatus(), req.getOrderNo(), req.getOrderId(), StaticDict.Cost_ModuleType.Second.getValue(),
                req.getOrderType(), req.getWhId(), req.getCompanyId(), req.getTenantId(), req.getOmsOrderCreateTime());
        return this.costForOut(trialReq, req.getTrackId(), addEt);
    }


    public TrialFreightRes costForOut(TrialOmsReq req, Long trackId, CostAddEt addEt) {
//        OrderOutboundDo et = orderOutboundDao.selectById(id);
        if (trackId != null && trackId != -1) {
            req.setLc(Collections.singletonList(new LcCodeRes(trackId, "", "")));
        } else if (trackId != null) {
            req.setAutoChooseCheap(1);
        }
//        WarehouseDo warehouseDo = warehouseService.getById(req.getWarehouseId());
        List<TrialFreightRes> resList = this.omsTrialFreightFee(req);
        double totalFee = 0d;
        List<CostItemEt> costItemEtList = new ArrayList<>();
        if (!resList.isEmpty() && resList.get(0).isSuccessFlag()) {
            totalFee += resList.get(0).getSurchargeFee() + resList.get(0).getLogBaseFee();
            for (SurchargeFeeRes surchargeFeeRes : resList.get(0).getSurchargeList()) {
                //运费这块 附加费
                costItemEtList.add(new CostItemEt(surchargeFeeRes.getItemName(), null, null, surchargeFeeRes.getFee()));
            }
        }
        //操作费
        OrderMsgForCostEt costEt = new OrderMsgForCostEt();
        costEt.setTrackId(trackId);
        List<SkuMsg> skuMsg = new ArrayList<>();
        for (TrialProductReq product : req.getProducts()) {
            if (Objects.isNull(product.getLength()) && Objects.isNull(product.getWmsLength())) {
                ProductDo productDo = productDao.selectById(product.getProductId());
                if (Objects.isNull(productDo)) {
                    continue;
                }
                BeanUtils.copyProperties(productDo, product);
            }
            if (product.getWmsLength() == null) {
                skuMsg.add(SkuMsg.builder().qty(product.getQuantity()).productId(product.getProductId())
                        .size(new Size(product.getHeight(), product.getHeightBs(), product.getLength(), product.getLengthBs(), product.getWidth(), product.getWidthBs(),
                                product.getWeight(), product.getWeightBs())).build());
            } else {
                skuMsg.add(SkuMsg.builder().qty(product.getQuantity()).productId(product.getProductId())
                        .size(new Size(product.getWmsHeight(), product.getWmsHeightBs(), product.getWmsLength(), product.getWmsLengthBs(), product.getWmsWidth(), product.getWmsWidthBs(),
                                product.getWmsWeight(), product.getWmsWeightBs())).build());
            }
        }
        costEt.setSkus(skuMsg);
        List<BoxMsg> boxes = new ArrayList<>();
        for (TrialBoxReq productDo : req.getBoxes()) {
            boxes.add(new BoxMsg(productDo.getQuantity(), new Size(productDo.getHeight(), productDo.getHeightBs(), productDo.getLength(), productDo.getLengthBs(), productDo.getWidth(), productDo.getWidthBs(),
                    productDo.getWeight(), productDo.getWeightBs()), productDo.getTrackNo()));
        }
        costEt.setBoxes(boxes);
//        costEt.setOrderType(StaticDict.Cost_Out_OrderType.First.getValue());
        costEt.setOrderType(addEt.getOrderType());
        //总体积总重量
        this.setTotalWeight(costEt);
        CostInfoEntity costInfoEntity = this.getCostInfo(addEt, costEt);
        if (costInfoEntity.getCostStatus() == 2) {
            totalFee += costInfoEntity.getCostTotal().doubleValue();
            if (costInfoEntity.getItems() != null) costItemEtList.addAll(costInfoEntity.getItems());
        }
        costInfoEntity.setCostTotal(new BigDecimal(totalFee));
        costInfoEntity.setItems(costItemEtList);
        costService.insertEntity(costInfoEntity, null);

        if (resList.isEmpty()) {
            return new TrialFreightRes("参数错误", "参数错误,请联系管理员");
        } else {
            return resList.get(0);
        }
    }


    public void setTotalWeight(OrderMsgForCostEt costEt) {
        double totalVolume = 0d, totalWeight = 0d, totalVolumeBs = 0d, totalWeightBs = 0d;
        for (SkuMsg sku : costEt.getSkus()) {
            Size productDo = sku.getSize();
            totalVolume += productDo.getLength().doubleValue() * productDo.getWidth().doubleValue() * productDo.getHeight().doubleValue() * sku.getQty();
            totalWeight += productDo.getWeight().doubleValue() * sku.getQty();
            totalVolumeBs += productDo.getLengthBs().doubleValue() * productDo.getWidthBs().doubleValue() * productDo.getHeightBs().doubleValue() * sku.getQty();
            totalWeightBs += productDo.getWeightBs().doubleValue() * sku.getQty();
        }
        //总体积总重量
        costEt.setTotalVolume(OrderMsgForCostEt.Dimension.builder().value(new BigDecimal(totalVolume)).valueBs(new BigDecimal(totalVolumeBs)).build());
        costEt.setTotalWeight(OrderMsgForCostEt.Dimension.builder().value(new BigDecimal(totalWeight)).valueBs(new BigDecimal(totalWeightBs)).build());
        costEt.setSkuKind((int) costEt.getSkus().stream().map(SkuMsg::getProductId).distinct().count());
        if (costEt.getBoxes() != null) {
            costEt.setBoxQty(costEt.getBoxes().stream().mapToInt(BoxMsg::getQty).sum());
        }
    }


    public SizeArrRes getSizeArr(FreightTempDo freightTempDo, OrderOutCostReq costReq) {
        TrialFreightUtilReq req = BeanConvert.INSTANCE.trialFreightUtilReq(costReq);
        req.setOrderLimit(1);

        return this.getSizeArr(freightTempDo, costReq);
    }


    public SizeArrRes getSizeArr(FreightTempDo freightTempDo, TrialFreightUtilReq req) {

        //计算尺寸 长 宽 高 重 计费重 体积重 体积
        Double[] sizeCm = new Double[]{0D, 0D, 0D, 0D, null, null, null};
        Double[] sizeIn = new Double[]{0D, 0D, 0D, 0D, null, null, null};
        double declarePrice = 0d;
        if (req.getGoodsType() == 1) {
            Double length = req.getLength(), width = req.getWidth(), height = req.getHeight(), weight = req.getWeight();
            if (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(req.getSizeUnit())) {
                this.getSize(length, width, height, weight, sizeCm);
                //先把参数转成物流费一样的单位
                length = (req.getLength() * StaticDict.OMP_Unit.getCoe(req.getSizeUnit()));
                width = (req.getWidth() * StaticDict.OMP_Unit.getCoe(req.getSizeUnit()));
                height = (req.getHeight() * StaticDict.OMP_Unit.getCoe(req.getSizeUnit()));
                //cm  重量就是 kg
                weight = (req.getWeight() * StaticDict.OMP_Unit.getCoe(StaticDict.OMP_Unit.Kg.getValue()));
                this.getSize(length, width, height, weight, sizeIn);
            } else {
                this.getSize(length, width, height, weight, sizeIn);
                //先把参数转成物流费一样的单位
                length = (req.getLength() * StaticDict.OMP_Unit.getCoe(req.getSizeUnit()));
                width = (req.getWidth() * StaticDict.OMP_Unit.getCoe(req.getSizeUnit()));
                height = (req.getHeight() * StaticDict.OMP_Unit.getCoe(req.getSizeUnit()));
                //in  重量就是 lb
                weight = (req.getWeight() * StaticDict.OMP_Unit.getCoe(StaticDict.OMP_Unit.Lb.getValue()));
                this.getSize(length, width, height, weight, sizeCm);
            }
        } else if (req.getGoodsType() == 2) {
//                req.setSizeUnit(freightTempDo.getSizeUnit());
            //sku 模式 把长宽高按大小排序
            Map<Long, ProductDo> collect = productDao.selectList(new LambdaQueryWrapper<ProductDo>().in(ProductDo::getId, req.getProducts().stream().map(TrialProductReq::getProductId).collect(Collectors.toList()))).stream().collect(Collectors.toMap(ProductDo::getId, i -> i));
            for (TrialProductReq product : req.getProducts()) {
                ProductDo productDo = collect.get(product.getProductId());
                if (productDo == null) throw new BizException(SysConstant.sku_not_exist_0, product.getSku());
                declarePrice += productDo.getDeclarePrice().doubleValue() * product.getQuantity();
                //公制
                if (productDo.getWmsWeight() != null) {//wms公制尺寸
                    this.setSizeArr(sizeCm, productDo.getWmsLength().doubleValue(), productDo.getWmsWidth().doubleValue(), productDo.getWmsHeight().doubleValue(), productDo.getWmsWeight().doubleValue(), product.getQuantity());

                } else {//OMS公制尺寸
                    this.setSizeArr(sizeCm, productDo.getLength().doubleValue(), productDo.getWidth().doubleValue(), productDo.getHeight().doubleValue(), productDo.getWeight().doubleValue(), product.getQuantity());
                }
                if (productDo.getWmsWeightBs() != null) {//WMS 英制尺寸
                    this.setSizeArr(sizeIn, productDo.getWmsLengthBs().doubleValue(), productDo.getWmsWidthBs().doubleValue(), productDo.getWmsHeightBs().doubleValue(), productDo.getWmsWeightBs().doubleValue(), product.getQuantity());

                } else {
                    this.setSizeArr(sizeIn, productDo.getLengthBs().doubleValue(), productDo.getWidthBs().doubleValue(), productDo.getHeightBs().doubleValue(), productDo.getWeightBs().doubleValue(), product.getQuantity());
                }
            }
        } else if (req.getGoodsType() == 3) {
            for (TrialBoxReq box : req.getBoxes()) {
                this.setSizeArr(sizeCm, box.getLength().doubleValue(), box.getWidth().doubleValue(), box.getHeight().doubleValue(), box.getWeight().doubleValue(), box.getQuantity());
                this.setSizeArr(sizeIn, box.getLengthBs().doubleValue(), box.getWidthBs().doubleValue(), box.getHeightBs().doubleValue(), box.getWeightBs().doubleValue(), box.getQuantity());
            }

        }
        if (freightTempDo.getCarryWeight() == 1) {
            sizeCm[3] = Math.ceil(sizeCm[3]);
            sizeIn[3] = Math.ceil(sizeIn[3]);
        }
        if (freightTempDo.getCarryBit() == 0) {
            //尺寸进位 55.9 * 55.2 * 12.5 -> 56 * 56 * 13
            sizeCm[0] = Math.ceil(sizeCm[0]);
            sizeCm[1] = Math.ceil(sizeCm[1]);
            sizeCm[2] = Math.ceil(sizeCm[2]);
            sizeIn[0] = Math.ceil(sizeIn[0]);
            sizeIn[1] = Math.ceil(sizeIn[1]);
            sizeIn[2] = Math.ceil(sizeIn[2]);
        }
        if (freightTempDo.getVolumeWeightCalculateWay() == 0) {
            //体积重 size[5]
            sizeCm[5] = sizeCm[0] * sizeCm[1] * sizeCm[2] / freightTempDo.getCoefficient();
            sizeIn[5] = sizeIn[0] * sizeIn[1] * sizeIn[2] / freightTempDo.getCoefficient();
            //计费重 重量和体积重取最大值
            sizeCm[4] = Math.max(sizeCm[3], sizeCm[5]);
            sizeIn[4] = Math.max(sizeIn[3], sizeIn[5]);
        } else if (freightTempDo.getVolumeWeightCalculateWay() == 1) {
            //体积重计算方式：三边和 ,计费重 体积重 和 实重都要 计费重在计算费用时 具体看取三边和 还是重量
            sizeCm[5] = sizeCm[0] + sizeCm[1] + sizeCm[2];
            sizeIn[5] = sizeIn[0] + sizeIn[1] + sizeIn[2];
        } else {
            //不计算  计费重就是实重， 无体积重
            sizeCm[4] = sizeCm[3];
            sizeIn[4] = sizeIn[3];
        }
        //体积
        sizeCm[6] = sizeCm[0] * sizeCm[1] * sizeCm[2] / 100000;
        sizeIn[6] = sizeIn[0] * sizeIn[1] * sizeIn[2] / 1728;
        return new SizeArrRes(sizeCm, sizeIn, declarePrice);
    }

}
